package com.electromagnetic.industry.software.manage.service.serviceimpl;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.text.StrFormatter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.electromagnetic.industry.software.common.enums.EffectFlagEnum;
import com.electromagnetic.industry.software.common.enums.PublishEnum;
import com.electromagnetic.industry.software.common.enums.TagTypeEnum;
import com.electromagnetic.industry.software.common.exception.BizException;
import com.electromagnetic.industry.software.manage.pojo.other.TreeNode;
import com.electromagnetic.industry.software.common.util.UserThreadLocal;
import com.electromagnetic.industry.software.manage.mapper.EdTagLibraryMapper;
import com.electromagnetic.industry.software.manage.pojo.models.EdTagLibrary;
import com.electromagnetic.industry.software.manage.pojo.resp.FileTagInfo;
import com.electromagnetic.industry.software.manage.pojo.resp.TagListVO;
import com.electromagnetic.industry.software.manage.service.EdTagLibraryService;
import com.electromagnetic.industry.software.manage.service.FileTagRelationService;
import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class EdTagLibraryServiceImpl extends ServiceImpl<EdTagLibraryMapper, EdTagLibrary> implements EdTagLibraryService {

    @Resource
    FileTagRelationService fileTagRelationService;


    /**
     * 新建标签组
     *
     * @param tagName
     * @param createdBy
     * @return
     */
    @Override
    public Boolean createTagGroup(String tagName, String createdBy) {

        Assert.isTrue(!checkNameExist(tagName), StrFormatter.format("该标签组 {} 已存在", tagName));
        // 查询当前最大排序值
        int maxOrder = selectMaxOrder(TagTypeEnum.GROUP.getCode(), "0");
        EdTagLibrary tagGroup = new EdTagLibrary();
        tagGroup.newInit();
        tagGroup.setParentId("0"); // 标签组父节点为"0"
        tagGroup.setType(TagTypeEnum.GROUP.getCode());
        tagGroup.setTagName(tagName);
        tagGroup.setOrderBy(maxOrder + 1); // 排在最后
        boolean isSuccess = this.save(tagGroup);
        if (isSuccess) {
            UserThreadLocal.setSuccessInfo("", tagGroup.getTagId(), StrFormatter.format("新建了标签组{}", tagName));
        }
        return isSuccess;
    }

    /**
     * 新建标签
     *
     * @param parentId
     * @param tagName
     * @param createdBy
     */
    @Override
    public Boolean createTag(String parentId, String tagName, String createdBy) {
        Assert.isTrue(!checkNameExist(tagName), StrFormatter.format("该标签名 {} 已存在", tagName));
        // 查询当前组内最大排序值
        int maxOrder = selectMaxOrder(TagTypeEnum.TAG.getCode(), parentId);
        EdTagLibrary tag = new EdTagLibrary();
        tag.newInit();
        tag.setParentId(parentId);
        tag.setType(TagTypeEnum.TAG.getCode()); // 标签
        tag.setTagName(tagName);
        tag.setOrderBy(maxOrder + 1); // 默认排序

        // 判断标签组有无发布，若发布，则标签已发布，若未发布，则标签未发布
        int isPublished = this.getById(parentId).getIsPublished();
        tag.setIsPublished(isPublished);

        tag.setCreatedBy(createdBy);
        boolean isSuccess = this.save(tag);
        if (isSuccess) {
            UserThreadLocal.setSuccessInfo("", tag.getTagId(), StrFormatter.format("新建了标签 {} ", tagName));
        }
        return isSuccess;
    }

    /**
     * 更新标签顺序
     *
     * @param tagId
     * @param newOrderBy
     */
    @Override
    @Transactional
    public Boolean updateTagOrder(String tagId, String newTagId, String newParentId, Integer newOrderBy, String updatedBy) {

        if (StringUtils.isEmpty(newParentId) || newOrderBy == null) {
            throw new IllegalArgumentException("缺少参数");
        }
        // 查询该标签
        EdTagLibrary tag = this.getOne(new LambdaQueryWrapper<EdTagLibrary>()
                .eq(EdTagLibrary::getTagId, tagId));
        // 查询交换顺序的标签/组
        EdTagLibrary newTag = this.getOne(new LambdaQueryWrapper<EdTagLibrary>()
                .eq(EdTagLibrary::getTagId, newTagId));

        Assert.notNull(tag, "此标签/标签组不存在");
        Assert.notNull(newTag, "无法将标签/标签组移动到此位置");

        // 若标签挪到空标签组下，newTagId为新标签组Id
        if (!tag.getType().equals(newTag.getType())) {
            if (tag.getType().equals(TagTypeEnum.TAG.getCode())) {
                newParentId = newTagId;
                newOrderBy = 1;
            } else {
                throw new BizException("标签组无法移动到标签下");
            }
        }

        String oldParentId = tag.getParentId();
        Integer oldOrderBy = tag.getOrderBy();
        // 是否更换了标签组
        boolean isMoveToNewGroup = !oldParentId.equals(newParentId);

        if (isMoveToNewGroup) {
            // 旧组重新排序
            int max = selectMaxOrder(tag.getType(), oldParentId) + 1;
            reorderTagGroup(oldParentId, oldOrderBy, max);

            // 新组重新排序
            max = selectMaxOrder(tag.getType(), newParentId) + 1;
            reorderTagGroup(newParentId, max, newOrderBy);
        } else {
            // 仅更新同组内的排序
            reorderTagGroup(oldParentId, oldOrderBy, newOrderBy);
        }

        // 更新当前标签的新排序值
        boolean isUpdated = this.update(new LambdaUpdateWrapper<EdTagLibrary>()
                .eq(EdTagLibrary::getTagId, tagId)
                .set(EdTagLibrary::getParentId, newParentId)
                .set(EdTagLibrary::getOrderBy, newOrderBy)
                .set(EdTagLibrary::getUpdatedBy, updatedBy));
        if (isUpdated) {
            UserThreadLocal.setSuccessInfo("", tagId, StrFormatter.format("更新了标签 {} 的排序", tag.getTagName()));
        }
        return isUpdated;
    }

    /**
     * 发布标签批量
     *
     * @param tagGroupIds
     */
    @Override
    @Transactional
    public Boolean batchPublishTagGroups(List<String> tagGroupIds) {

        Assert.notEmpty(tagGroupIds, "参数 tagGroupIds 不能为空");
        this.update(new LambdaUpdateWrapper<EdTagLibrary>()
                .in(EdTagLibrary::getTagId, tagGroupIds)
                .eq(EdTagLibrary::getType, TagTypeEnum.GROUP.getCode()) // 只更新标签组
                .set(EdTagLibrary::getIsPublished, PublishEnum.PUBLISHED.getCode()));

        this.update(new LambdaUpdateWrapper<EdTagLibrary>()
                .in(EdTagLibrary::getParentId, tagGroupIds) // 父 ID 是传入的标签组
                .eq(EdTagLibrary::getType, TagTypeEnum.TAG.getCode()) // 只更新标签
                .set(EdTagLibrary::getIsPublished, PublishEnum.PUBLISHED.getCode()));
        UserThreadLocal.setSuccessInfo("", "", "发布了标签");
        return true;
    }

    /**
     * 废除标签
     *
     * @param tagId
     * @return
     */
    @Override
    @Transactional
    public Boolean deleteTagOrGroup(String tagId) {
        EdTagLibrary tag = this.getOne(
                Wrappers.lambdaQuery(EdTagLibrary.class)
                        .eq(EdTagLibrary::getTagId, tagId)
                        .eq(EdTagLibrary::getEffectFlag, EffectFlagEnum.EFFECT.code)
        );
        Assert.notNull(tag, "标签不存在");
        // 如果是标签组，级联删除其下的所有标签
        if (Objects.equals(tag.getType(), TagTypeEnum.GROUP.getCode())) {

            // 逻辑删除子标签
            this.update(
                    Wrappers.lambdaUpdate(EdTagLibrary.class)
                            .set(EdTagLibrary::getEffectFlag, EffectFlagEnum.NOT_EFFECTIVE.code)
                            .eq(EdTagLibrary::getParentId, tagId)
            );

            // 查询所有子标签
            List<EdTagLibrary> tags = this.list(new LambdaQueryWrapper<EdTagLibrary>()
                    .eq(EdTagLibrary::getParentId, tagId));
            // 逻辑删除子标签的关联关系
            if (!tags.isEmpty()) {
                for (EdTagLibrary childTag : tags) {
                    fileTagRelationService.logicRemove(null, childTag.getTagId());
                }
            }
        }

        // 逻辑删除当前标签/组
        boolean mainDeleted = this.update(
                Wrappers.lambdaUpdate(EdTagLibrary.class)
                        .set(EdTagLibrary::getEffectFlag, EffectFlagEnum.NOT_EFFECTIVE.code)
                        .eq(EdTagLibrary::getTagId, tagId)
        );
        // 逻辑删除本身的关联关系
        fileTagRelationService.logicRemove(null, tagId);

        if (mainDeleted) {
            UserThreadLocal.setSuccessInfo("", tagId, StrFormatter.format("删除了标签 {} ", tag.getTagName()));
        }
        return mainDeleted;
    }

    /**
     * 标签数据
     *
     * @return
     */
    @Override
    public List<TagListVO> listTagsWithGroups() {

        // 查询所有标签组
        List<EdTagLibrary> groups = this.list(new LambdaQueryWrapper<EdTagLibrary>()
                .eq(EdTagLibrary::getType, TagTypeEnum.GROUP.getCode())
                .eq(EdTagLibrary::getEffectFlag, EffectFlagEnum.EFFECT.code)
                .orderByAsc(EdTagLibrary::getOrderBy));

        // 查询所有标签
        List<EdTagLibrary> tags = this.list(new LambdaQueryWrapper<EdTagLibrary>()
                .eq(EdTagLibrary::getType, TagTypeEnum.TAG.getCode())
                .eq(EdTagLibrary::getEffectFlag, EffectFlagEnum.EFFECT.code)
                .orderByAsc(EdTagLibrary::getOrderBy));

        // 构造分组数据
        Map<String, List<EdTagLibrary>> tagsGrouped = tags.stream()
                .collect(Collectors.groupingBy(EdTagLibrary::getParentId));

        List<TagListVO> result = new ArrayList<>();
        for (EdTagLibrary group : groups) {
            TagListVO vo = new TagListVO();
            BeanUtils.copyProperties(group, vo);
            vo.setChildren(tagsGrouped.getOrDefault(group.getTagId(), new ArrayList<>()));
            result.add(vo);
        }
        UserThreadLocal.setSuccessInfo("", "", "获取了标签数据");
        return result;
    }

    /**
     * 更新标签信息
     *
     * @param tagId
     * @param tagName
     * @param updatedBy
     * @return 更新结果
     */
    @Override
    public Boolean updateTagInfo(String tagId, String tagName, String updatedBy) {
        Assert.isTrue(!checkNameExist(tagName), StrFormatter.format("该标签/标签组名 {} 已存在", tagName));
        LambdaUpdateWrapper<EdTagLibrary> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(EdTagLibrary::getTagId, tagId)
                .set(EdTagLibrary::getTagName, tagName)
                .set(EdTagLibrary::getUpdatedBy, updatedBy);
        boolean isUpdated = this.update(updateWrapper);
        if (isUpdated) {
            UserThreadLocal.setSuccessInfo("", tagId, StrFormatter.format("更新了标签 {} 信息", tagName));
        }
        return isUpdated;
    }

    /**
     * 重排标签组
     */
    private void reorderTagGroup(String parentId, Integer oldOrderBy, Integer newOrderBy) {

        boolean isMoveDown = newOrderBy > oldOrderBy;

        LambdaUpdateWrapper<EdTagLibrary> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(EdTagLibrary::getParentId, parentId);

        if (isMoveDown) {
            updateWrapper.setSql("order_by = order_by - 1")
                    .gt(EdTagLibrary::getOrderBy, oldOrderBy)
                    .le(EdTagLibrary::getOrderBy, newOrderBy);
        } else {
            updateWrapper.setSql("order_by = order_by + 1")
                    .ge(EdTagLibrary::getOrderBy, newOrderBy)
                    .lt(EdTagLibrary::getOrderBy, oldOrderBy);
        }
        this.update(updateWrapper);
    }

    /**
     * 构建标签树
     *
     * @return
     */
    @Override
    public List<TreeNode> listTagTree() {

        LambdaQueryWrapper<EdTagLibrary> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(EdTagLibrary::getIsPublished, PublishEnum.PUBLISHED.getCode())
                .eq(EdTagLibrary::getEffectFlag, EffectFlagEnum.EFFECT.code);
        List<EdTagLibrary> tags = this.list(queryWrapper);
        Map<String, TreeNode> map = new HashMap<>();
        List<TreeNode> list = new ArrayList<>();

        for (EdTagLibrary tag : tags) {
            TreeNode node = null;
            if (tag.getType().equals(TagTypeEnum.GROUP.getCode())) {
                node = TreeNode.builder()
                        .title(tag.getTagName())
                        .key(tag.getTagId())
                        .children(new ArrayList<>())
                        .build();
            } else if (tag.getType().equals(TagTypeEnum.TAG.getCode())) {
                node = TreeNode.builder()
                        .title(tag.getTagName())
                        .key(tag.getTagId())
                        .children(null)
                        .build();
            }

            map.put(tag.getTagId(), node);
        }

        for (EdTagLibrary tag : tags) {
            if (tag.getType().equals(TagTypeEnum.GROUP.getCode())) {
                list.add(map.get(tag.getTagId()));
            } else if (tag.getType().equals(TagTypeEnum.TAG.getCode())) {
                TreeNode parentNode = map.get(tag.getParentId());
                if (parentNode != null) {
                    parentNode.getChildren().add(map.get(tag.getTagId()));
                }
            }
        }
        UserThreadLocal.setSuccessInfo("", "", "查看标签树成功");
        return list;
    }

    /**
     * 获取所有标签
     *
     * @return
     */
    @Override
    public List<FileTagInfo> listAllTags() {
        LambdaQueryWrapper<EdTagLibrary> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(EdTagLibrary::getIsPublished, PublishEnum.PUBLISHED.getCode())
                .eq(EdTagLibrary::getType, TagTypeEnum.TAG.getCode())
                .eq(EdTagLibrary::getEffectFlag, EffectFlagEnum.EFFECT.code);
        return this.list(queryWrapper).stream()
                .map(tag -> {
                    FileTagInfo info = new FileTagInfo();
                    BeanUtils.copyProperties(tag, info);
                    return info;
                }).toList();
    }

    /**
     * 校验名字是否重复
     *
     * @param tagName
     * @return
     */
    private boolean checkNameExist(String tagName) {
        LambdaQueryWrapper<EdTagLibrary> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(EdTagLibrary::getTagName, tagName).eq(EdTagLibrary::getEffectFlag, EffectFlagEnum.EFFECT.code);
        return this.count(queryWrapper) > 0;
    }

    /**
     * 计算顺序
     *
     * @return maxOrder
     */
    private int selectMaxOrder(int typeCode, String parentId) {
        // 查询当前最大排序值
        // int maxOrder = Optional.ofNullable(this.getBaseMapper().selectMaxOrder(typeCode, parentId)).orElse(0);
        return this.baseMapper.selectObjs(
                        Wrappers.lambdaQuery(EdTagLibrary.class)
                                .select(EdTagLibrary::getOrderBy)
                                .eq(EdTagLibrary::getType, typeCode)
                                .eq(EdTagLibrary::getParentId, parentId)
                                .eq(EdTagLibrary::getEffectFlag, EffectFlagEnum.EFFECT.code)
                                .orderByDesc(EdTagLibrary::getOrderBy)
                                .last("LIMIT 1") // 取最大值
                ).stream()
                .findFirst()
                .map(obj -> (Integer) obj)
                .orElse(0); // 处理空值
    }
}

